package com.yuji.aacar.widgets.pulltorefresh.indicator;

public class PtrTensionIndicator extends PtrIndicator {

    private float DRAG_RATE = 0.5f;
    private float mDownY;
    private float mDownPos;
    private float mOneHeaderHeight = 0;
    private float mOneFooterHeight = 0;
    private float mOneHeight = 0;

    private float mCurrentDragPercent;

    private int mReleasePos;
    private float mReleasePercent = -1;

    private byte state;

    private boolean canHeaderMoveDown;
    private boolean canFooterMoveUp;

    public void setState(byte state) {
        this.state = state;
    }

    public void setState(boolean canHeaderMoveDown, boolean canFooterMoveUp) {
        this.canHeaderMoveDown = canHeaderMoveDown;
        this.canFooterMoveUp = canFooterMoveUp;
    }

    @Override
    public void onPressDown(float x, float y) {
        super.onPressDown(x, y);
        mDownY = y;
        mDownPos = getCurrentPosY();
    }

    @Override
    public void onRelease() {
        super.onRelease();
        mReleasePos = getCurrentPosY();
        mReleasePercent = mCurrentDragPercent;
    }

    @Override
    public void onUIRefreshComplete() {
        mReleasePos = getCurrentPosY();
        mReleasePercent = getOverDragPercent();
    }

    @Override
    public void setHeaderHeight(int height) {
        super.setHeaderHeight(height);
        mOneHeaderHeight = height * 4f / 5;
    }

    @Override
    public void setFooterHeight(int height) {
        super.setFooterHeight(height);
        mOneFooterHeight = height;
    }

    @Override
    protected void processOnMove(float currentX, float currentY, float offsetX, float offsetY) {
        if (isHeader()) {
            mOneHeight = mOneHeaderHeight;
            if (currentY < mDownY) {
//                mDownY = currentY;
                super.processOnMove(currentX, currentY, offsetX, offsetY);
                return;
            }
        } else {
//            mOneHeight = mOneFooterHeight;
//            if (currentY > mDownY) {
//                mDownY = currentY;
//                super.processOnMove(currentX, currentY, offsetX, offsetY);
//                return;
//            }
            super.processOnMove(currentX, currentY, offsetX, offsetY);
            return;
        }

        // distance from top
        if (!canFooterMoveUp && !canHeaderMoveDown) {
            mDownY = currentY;
        }
        final float scrollTop = (currentY - mDownY) * DRAG_RATE + mDownPos;
        final float currentDragPercent = scrollTop / mOneHeight;

        if (currentDragPercent < 0 && isHeader()) {
            setOffset(offsetX, 0);
            return;
        }

        if (currentDragPercent > 0 && !isHeader()) {
            setOffset(offsetX, 0);
            return;
        }

        mCurrentDragPercent = currentDragPercent;

        float boundedDragPercent = Math.min(1f, Math.abs(currentDragPercent));
        float extraOS = scrollTop - mOneHeight;

        float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, mOneHeight * 2) / mOneHeight);

        float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;
        float extraMove = (mOneHeight) * tensionPercent / 2;
        int targetY = (int) ((mOneHeight * boundedDragPercent) + extraMove);

        int change;
        if (isHeader()) {
            change = targetY - getCurrentPosY();
        } else {
            change = getCurrentPosY() - targetY;
        }

        setOffset(currentX, change);
    }

    private float offsetToTarget(float scrollTop) {

        // distance from top
        final float currentDragPercent = scrollTop / mOneHeight;

        mCurrentDragPercent = currentDragPercent;

        // 0 ~ 1
        float boundedDragPercent = Math.min(1f, Math.abs(currentDragPercent));
        float extraOS = scrollTop - mOneHeight;

        // 0 ~ 2
        // if extraOS lower than 0, which means scrollTop lower than mOneHeight, tensionSlingshotPercent will be 0.
        float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, mOneHeight * 2) / mOneHeight);

        float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;
        float extraMove = (mOneHeight) * tensionPercent / 2;
        int targetY = (int) ((mOneHeight * boundedDragPercent) + extraMove);

        return 0;
    }

    @Override
    public int getOffsetToKeepHeaderWhileLoading() {
        return getOffsetToRefresh();
    }

    @Override
    public int getOffsetToRefresh() {
        if (isHeader()) {
            return (int) mOneHeaderHeight;
        } else {
            return (int) mOneFooterHeight;
        }
    }

    public float getOverDragPercent() {
        if (isUnderTouch()) {
            return mCurrentDragPercent;
        } else {
            if (mReleasePercent <= 0) {
                return 1.0f * getCurrentPosY() / getOffsetToKeepHeaderWhileLoading();
            }
            // after release
            return mReleasePercent * getCurrentPosY() / mReleasePos;
        }
    }
}
